/**

 @Name：layui.table 表格操作
 @Author：贤心
 @License：MIT
    
 */

layui.define(['laytpl', 'laypage', 'layer', 'form', 'util'], function(exports) {
	"use strict";

	var $ = layui.$
		, laytpl = layui.laytpl
		, laypage = layui.laypage
		, layer = layui.layer
		, form = layui.form
		, util = layui.util
		, hint = layui.hint()
		, device = layui.device()

		//外部接口
		, table = {
			config: {
				checkName: 'LAY_CHECKED' //是否选中状态的字段名
				, indexName: 'LAY_TABLE_INDEX' //下标索引名
			} //全局配置项
			, cache: {} //数据缓存
			, index: layui.table ? (layui.table.index + 10000) : 0

			//设置全局项
			, set: function(options) {
				var that = this;
				that.config = $.extend({}, that.config, options);
				return that;
			}

			//事件监听
			, on: function(events, callback) {
				return layui.onevent.call(this, MOD_NAME, events, callback);
			}
		}

		//操作当前实例
		, thisTable = function() {
			var that = this
				, options = that.config
				, id = options.id || options.index;

			if (id) {
				thisTable.that[id] = that; //记录当前实例对象
				thisTable.config[id] = options; //记录当前实例配置项
			}

			return {
				config: options
				, reload: function(options) {
					that.reload.call(that, options);
				}
				, setColsWidth: function() {
					that.setColsWidth.call(that);
				}
				, resize: function() { //重置表格尺寸/结构
					that.resize.call(that);
				}
			}
		}

		//获取当前实例配置项
		, getThisTableConfig = function(id) {
			var config = thisTable.config[id];
			if (!config) hint.error('The ID option was not found in the table instance');
			return config || null;
		}

		//解析自定义模板数据
		, parseTempData = function(item3, content, tplData, text) { //表头数据、原始内容、表体数据、是否只返回文本
			var str = item3.templet ? function() {
				return typeof item3.templet === 'function'
					? item3.templet(tplData)
					: laytpl($(item3.templet).html() || String(content)).render(tplData)
			}() : content;
			return text ? $('<div>' + str + '</div>').text() : str;
		}

		//字符常量
		, MOD_NAME = 'table', ELEM = '.layui-table', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled', NONE = 'layui-none'

		, ELEM_VIEW = 'layui-table-view', ELEM_TOOL = '.layui-table-tool', ELEM_BOX = '.layui-table-box', ELEM_INIT = '.layui-table-init', ELEM_HEADER = '.layui-table-header', ELEM_BODY = '.layui-table-body', ELEM_MAIN = '.layui-table-main', ELEM_FIXED = '.layui-table-fixed', ELEM_FIXL = '.layui-table-fixed-l', ELEM_FIXR = '.layui-table-fixed-r', ELEM_TOTAL = '.layui-table-total', ELEM_PAGE = '.layui-table-page', ELEM_SORT = '.layui-table-sort', ELEM_EDIT = 'layui-table-edit', ELEM_HOVER = 'layui-table-hover'

		//thead区域模板
		, TPL_HEADER = function(options) {
			var rowCols = '{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';

			options = options || {};
			return ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
				, '{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
				, '<thead>'
				, '{{# layui.each(d.data.cols, function(i1, item1){ }}'
				, '<tr>'
				, '{{# layui.each(item1, function(i2, item2){ }}'
				, '{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}'
				, '{{# if(item2.fixed === "right"){ right = true; } }}'
				, function() {
					if (options.fixed && options.fixed !== 'right') {
						return '{{# if(item2.fixed && item2.fixed !== "right"){ }}';
					}
					if (options.fixed === 'right') {
						return '{{# if(item2.fixed === "right"){ }}';
					}
					return '';
				}()
				, '{{# var isSort = !(item2.colGroup) && item2.sort; }}'
				, '<th data-field="{{ item2.field||i2 }}" data-key="{{d.index}}-{{i1}}-{{i2}}" {{# if( item2.parentKey){ }}data-parentkey="{{ item2.parentKey }}"{{# } }} {{# if(item2.minWidth){ }}data-minwidth="{{item2.minWidth}}"{{# } }} ' + rowCols + ' {{# if(item2.unresize || item2.colGroup){ }}data-unresize="true"{{# } }} class="{{# if(item2.hide){ }}layui-hide{{# } }}{{# if(isSort){ }} layui-unselect{{# } }}{{# if(!item2.field){ }} layui-table-col-special{{# } }}">'
				, '<div class="layui-table-cell laytable-cell-'
				, '{{# if(item2.colGroup){ }}'
				, 'group'
				, '{{# } else { }}'
				, '{{d.index}}-{{i1}}-{{i2}}'
				, '{{# if(item2.type !== "normal"){ }}'
				, ' laytable-cell-{{ item2.type }}'
				, '{{# } }}'
				, '{{# } }}'
				, '" {{#if(item2.align){}}align="{{item2.align}}"{{#}}}>'
				, '{{# if(item2.type === "checkbox"){ }}' //复选框
				, '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-filter="layTableAllChoose" {{# if(item2[d.data.checkName]){ }}checked{{# }; }}>'
				, '{{# } else { }}'
				, '<span>{{item2.title||""}}</span>'
				, '{{# if(isSort){ }}'
				, '<span class="layui-table-sort layui-inline"><i class="layui-edge layui-table-sort-asc" title="升序"></i><i class="layui-edge layui-table-sort-desc" title="降序"></i></span>'
				, '{{# } }}'
				, '{{# } }}'
				, '</div>'
				, '</th>'
				, (options.fixed ? '{{# }; }}' : '')
				, '{{# }); }}'
				, '</tr>'
				, '{{# }); }}'
				, '</thead>'
				, '</table>'].join('');
		}

		//tbody区域模板
		, TPL_BODY = ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
			, '{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
			, '<tbody></tbody>'
			, '</table>'].join('')

		//主模板
		, TPL_MAIN = ['<div class="layui-form layui-border-box {{d.VIEW_CLASS}}" lay-filter="LAY-table-{{d.index}}" lay-id="{{ d.data.id }}" style="{{# if(d.data.width){ }}width:{{d.data.width}}px;{{# } }} {{# if(d.data.height){ }}height:{{d.data.height}}px;{{# } }}">'

			, '{{# if(d.data.toolbar){ }}'
			, '<div class="layui-table-tool">'
			, '<div class="layui-table-tool-temp"></div>'
			, '<div class="layui-table-tool-self"></div>'
			, '</div>'
			, '{{# } }}'

			, '<div class="layui-table-box">'
			, '{{# if(d.data.loading){ }}'
			, '<div class="layui-table-init" style="background-color: #fff;">'
			, '<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>'
			, '</div>'
			, '{{# } }}'

			, '{{# var left, right; }}'
			, '<div class="layui-table-header">'
			, TPL_HEADER()
			, '</div>'
			, '<div class="layui-table-body layui-table-main">'
			, TPL_BODY
			, '</div>'

			, '{{# if(left){ }}'
			, '<div class="layui-table-fixed layui-table-fixed-l">'
			, '<div class="layui-table-header">'
			, TPL_HEADER({ fixed: true })
			, '</div>'
			, '<div class="layui-table-body">'
			, TPL_BODY
			, '</div>'
			, '</div>'
			, '{{# }; }}'

			, '{{# if(right){ }}'
			, '<div class="layui-table-fixed layui-table-fixed-r">'
			, '<div class="layui-table-header">'
			, TPL_HEADER({ fixed: 'right' })
			, '<div class="layui-table-mend"></div>'
			, '</div>'
			, '<div class="layui-table-body">'
			, TPL_BODY
			, '</div>'
			, '</div>'
			, '{{# }; }}'
			, '</div>'

			, '{{# if(d.data.totalRow){ }}'
			, '<div class="layui-table-total">'
			, '<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
			, '{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
			, '<tbody><tr><td><div class="layui-table-cell" style="visibility: hidden;">Total</div></td></tr></tbody>'
			, '</table>'
			, '</div>'
			, '{{# } }}'

			, '{{# if(d.data.page){ }}'
			, '<div class="layui-table-page">'
			, '<div id="layui-table-page{{d.index}}"></div>'
			, '</div>'
			, '{{# } }}'

			, '<style>'
			, '{{# layui.each(d.data.cols, function(i1, item1){'
			, 'layui.each(item1, function(i2, item2){ }}'
			, '.laytable-cell-{{d.index}}-{{i1}}-{{i2}}{ '
			, '{{# if(item2.width){ }}'
			, 'width: {{item2.width}}px;'
			, '{{# } }}'
			, ' }'
			, '{{# });'
			, '}); }}'
			, '</style>'
			, '</div>'].join('')

		, _WIN = $(window)
		, _DOC = $(document)

		//构造器
		, Class = function(options) {
			var that = this;
			that.index = ++table.index;
			that.config = $.extend({}, that.config, table.config, options);
			that.render();
		};

	//默认配置
	Class.prototype.config = {
		limit: 10 //每页显示的数量
		, loading: true //请求数据时，是否显示loading
		, cellMinWidth: 60 //所有单元格默认最小宽度
		, defaultToolbar: ['filter', 'exports', 'print'] //工具栏右侧图标
		, autoSort: true //是否前端自动排序。如果否，则需自主排序（通常为服务端处理好排序）
		, text: {
			none: '无数据'
		}
	};

	//表格渲染
	Class.prototype.render = function() {
		var that = this
			, options = that.config;

		options.elem = $(options.elem);
		options.where = options.where || {};
		options.id = options.id || options.elem.attr('id') || that.index;

		//请求参数的自定义格式
		options.request = $.extend({
			pageName: 'page'
			, limitName: 'limit'
		}, options.request)

		//响应数据的自定义格式
		options.response = $.extend({
			statusName: 'code' //规定数据状态的字段名称
			, statusCode: 0 //规定成功的状态码
			, msgName: 'msg' //规定状态信息的字段名称
			, dataName: 'data' //规定数据总数的字段名称
			, totalRowName: 'totalRow' //规定数据统计的字段名称
			, countName: 'count'
		}, options.response);

		//如果 page 传入 laypage 对象
		if (typeof options.page === 'object') {
			options.limit = options.page.limit || options.limit;
			options.limits = options.page.limits || options.limits;
			that.page = options.page.curr = options.page.curr || 1;
			delete options.page.elem;
			delete options.page.jump;
		}

		if (!options.elem[0]) return that;

		//高度铺满：full-差距值
		if (options.height && /^full-\d+$/.test(options.height)) {
			that.fullHeightGap = options.height.split('-')[1];
			options.height = _WIN.height() - that.fullHeightGap;
		}

		//初始化一些参数
		that.setInit();

		//开始插入替代元素
		var othis = options.elem
			, hasRender = othis.next('.' + ELEM_VIEW)

			//主容器
			, reElem = that.elem = $(laytpl(TPL_MAIN).render({
				VIEW_CLASS: ELEM_VIEW
				, data: options
				, index: that.index //索引
			}));

		options.index = that.index;
		that.key = options.id || options.index;

		//生成替代元素
		hasRender[0] && hasRender.remove(); //如果已经渲染，则Rerender
		othis.after(reElem);

		//各级容器
		that.layTool = reElem.find(ELEM_TOOL);
		that.layBox = reElem.find(ELEM_BOX);
		that.layHeader = reElem.find(ELEM_HEADER);
		that.layMain = reElem.find(ELEM_MAIN);
		that.layBody = reElem.find(ELEM_BODY);
		that.layFixed = reElem.find(ELEM_FIXED);
		that.layFixLeft = reElem.find(ELEM_FIXL);
		that.layFixRight = reElem.find(ELEM_FIXR);
		that.layTotal = reElem.find(ELEM_TOTAL);
		that.layPage = reElem.find(ELEM_PAGE);

		//初始化工具栏
		that.renderToolbar();

		//让表格平铺
		that.fullSize();

		//如果多级表头，则填补表头高度
		if (options.cols.length > 1) {
			//补全高度
			var th = that.layFixed.find(ELEM_HEADER).find('th');
			th.height(that.layHeader.height() - 1 - parseFloat(th.css('padding-top')) - parseFloat(th.css('padding-bottom')));
		}

		that.pullData(that.page); //请求数据
		that.events(); //事件
	};

	//根据列类型，定制化参数
	Class.prototype.initOpts = function(item) {
		var that = this
			, options = that.config
			, initWidth = {
				checkbox: 48
				, radio: 48
				, space: 15
				, numbers: 40
			};

		//让 type 参数兼容旧版本
		if (item.checkbox) item.type = "checkbox";
		if (item.space) item.type = "space";
		if (!item.type) item.type = "normal";

		if (item.type !== "normal") {
			item.unresize = true;
			item.width = item.width || initWidth[item.type];
		}
	};

	//初始化一些参数
	Class.prototype.setInit = function(type) {
		var that = this
			, options = that.config;

		options.clientWidth = options.width || function() { //获取容器宽度
			//如果父元素宽度为0（一般为隐藏元素），则继续查找上层元素，直到找到真实宽度为止
			var getWidth = function(parent) {
				var width, isNone;
				parent = parent || options.elem.parent()
				width = parent.width();
				try {
					isNone = parent.css('display') === 'none';
				} catch (e) { }
				if (parent[0] && (!width || isNone)) return getWidth(parent.parent());
				return width;
			};
			return getWidth();
		}();

		if (type === 'width') return options.clientWidth;

		//初始化列参数
		layui.each(options.cols, function(i1, item1) {
			layui.each(item1, function(i2, item2) {

				//如果列参数为空，则移除
				if (!item2) {
					item1.splice(i2, 1);
					return;
				}

				item2.key = i1 + '-' + i2;
				item2.hide = item2.hide || false;

				//设置列的父列索引
				//如果是组合列，则捕获对应的子列
				if (item2.colGroup || item2.colspan > 1) {
					var childIndex = 0;
					layui.each(options.cols[i1 + 1], function(i22, item22) {
						//如果子列已经被标注为{HAS_PARENT}，或者子列累计 colspan 数等于父列定义的 colspan，则跳出当前子列循环
						if (item22.HAS_PARENT || (childIndex > 1 && childIndex == item2.colspan)) return;

						item22.HAS_PARENT = true;
						item22.parentKey = i1 + '-' + i2;

						childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1);
					});
					item2.colGroup = true; //标注是组合列
				}

				//根据列类型，定制化参数
				that.initOpts(item2);
			});
		});

	};

	//初始工具栏
	Class.prototype.renderToolbar = function() {
		var that = this
			, options = that.config

		//添加工具栏左侧模板
		var leftDefaultTemp = [
			'<div class="layui-inline" lay-event="add"><i class="layui-icon layui-icon-add-1"></i></div>'
			, '<div class="layui-inline" lay-event="update"><i class="layui-icon layui-icon-edit"></i></div>'
			, '<div class="layui-inline" lay-event="delete"><i class="layui-icon layui-icon-delete"></i></div>'
		].join('')
			, elemToolTemp = that.layTool.find('.layui-table-tool-temp');

		if (options.toolbar === 'default') {
			elemToolTemp.html(leftDefaultTemp);
		} else if (typeof options.toolbar === 'string') {
			var toolbarHtml = $(options.toolbar).html() || '';
			toolbarHtml && elemToolTemp.html(
				laytpl(toolbarHtml).render(options)
			);
		}

		//添加工具栏右侧面板
		var layout = {
			filter: {
				title: '筛选列'
				, layEvent: 'LAYTABLE_COLS'
				, icon: 'layui-icon-cols'
			}
			, exports: {
				title: '导出'
				, layEvent: 'LAYTABLE_EXPORT'
				, icon: 'layui-icon-export'
			}
			, print: {
				title: '打印'
				, layEvent: 'LAYTABLE_PRINT'
				, icon: 'layui-icon-print'
			}
		}, iconElem = [];

		if (typeof options.defaultToolbar === 'object') {
			layui.each(options.defaultToolbar, function(i, item) {
				var thisItem = typeof item === 'string' ? layout[item] : item;
				if (thisItem) {
					iconElem.push('<div class="layui-inline" title="' + thisItem.title + '" lay-event="' + thisItem.layEvent + '">'
						+ '<i class="layui-icon ' + thisItem.icon + '"></i>'
						+ '</div>');
				}
			});
		}
		that.layTool.find('.layui-table-tool-self').html(iconElem.join(''));
	}

	//同步表头父列的相关值
	Class.prototype.setParentCol = function(hide, parentKey) {
		var that = this
			, options = that.config

			, parentTh = that.layHeader.find('th[data-key="' + options.index + '-' + parentKey + '"]') //获取父列元素
			, parentColspan = parseInt(parentTh.attr('colspan')) || 0;

		if (parentTh[0]) {
			var arrParentKey = parentKey.split('-')
				, getThisCol = options.cols[arrParentKey[0]][arrParentKey[1]];

			hide ? parentColspan-- : parentColspan++;

			parentTh.attr('colspan', parentColspan);
			parentTh[parentColspan < 1 ? 'addClass' : 'removeClass'](HIDE);

			getThisCol.colspan = parentColspan; //同步 colspan 参数
			getThisCol.hide = parentColspan < 1; //同步 hide 参数

			//递归，继续往上查询是否有父列
			var nextParentKey = parentTh.data('parentkey');
			nextParentKey && that.setParentCol(hide, nextParentKey);
		}
	};

	//多级表头补丁
	Class.prototype.setColsPatch = function() {
		var that = this
			, options = that.config

		//同步表头父列的相关值
		layui.each(options.cols, function(i1, item1) {
			layui.each(item1, function(i2, item2) {
				if (item2.hide) {
					that.setParentCol(item2.hide, item2.parentKey);
				}
			});
		});
	};

	//动态分配列宽
	Class.prototype.setColsWidth = function() {
		var that = this
			, options = that.config
			, colNums = 0 //列个数
			, autoColNums = 0 //自动列宽的列个数
			, autoWidth = 0 //自动列分配的宽度
			, countWidth = 0 //所有列总宽度和
			, cntrWidth = that.setInit('width');

		//统计列个数
		that.eachCols(function(i, item) {
			item.hide || colNums++;
		});

		//减去边框差和滚动条宽
		cntrWidth = cntrWidth - function() {
			return (options.skin === 'line' || options.skin === 'nob') ? 2 : colNums + 1;
		}() - that.getScrollWidth(that.layMain[0]) - 1;

		//计算自动分配的宽度
		var getAutoWidth = function(back) {
			//遍历所有列
			layui.each(options.cols, function(i1, item1) {
				layui.each(item1, function(i2, item2) {
					var width = 0
						, minWidth = item2.minWidth || options.cellMinWidth; //最小宽度

					if (!item2) {
						item1.splice(i2, 1);
						return;
					}

					if (item2.colGroup || item2.hide) return;

					if (!back) {
						width = item2.width || 0;
						if (/\d+%$/.test(width)) { //列宽为百分比
							width = Math.floor((parseFloat(width) / 100) * cntrWidth);
							width < minWidth && (width = minWidth);
						} else if (!width) { //列宽未填写
							item2.width = width = 0;
							autoColNums++;
						}
					} else if (autoWidth && autoWidth < minWidth) {
						autoColNums--;
						width = minWidth;
					}

					if (item2.hide) width = 0;
					countWidth = countWidth + width;
				});
			});

			//如果未填充满，则将剩余宽度平分
			(cntrWidth > countWidth && autoColNums) && (
				autoWidth = (cntrWidth - countWidth) / autoColNums
			);
		}

		getAutoWidth();
		getAutoWidth(true); //重新检测分配的宽度是否低于最小列宽

		//记录自动列数
		that.autoColNums = autoColNums;

		//设置列宽
		that.eachCols(function(i3, item3) {
			var minWidth = item3.minWidth || options.cellMinWidth;
			if (item3.colGroup || item3.hide) return;

			//给位分配宽的列平均分配宽
			if (item3.width === 0) {
				that.getCssRule(options.index + '-' + item3.key, function(item) {
					item.style.width = Math.floor(autoWidth >= minWidth ? autoWidth : minWidth) + 'px';
				});
			}

			//给设定百分比的列分配列宽
			else if (/\d+%$/.test(item3.width)) {
				that.getCssRule(options.index + '-' + item3.key, function(item) {
					item.style.width = Math.floor((parseFloat(item3.width) / 100) * cntrWidth) + 'px';
				});
			}
		});

		//填补 Math.floor 造成的数差
		var patchNums = that.layMain.width() - that.getScrollWidth(that.layMain[0])
			- that.layMain.children('table').outerWidth();

		if (that.autoColNums && patchNums >= -colNums && patchNums <= colNums) {
			var getEndTh = function(th) {
				var field;
				th = th || that.layHeader.eq(0).find('thead th:last-child')
				field = th.data('field');
				if (!field && th.prev()[0]) {
					return getEndTh(th.prev())
				}
				return th
			}
				, th = getEndTh()
				, key = th.data('key');

			that.getCssRule(key, function(item) {
				var width = item.style.width || th.outerWidth();
				item.style.width = (parseFloat(width) + patchNums) + 'px';

				//二次校验，如果仍然出现横向滚动条（通常是 1px 的误差导致）
				if (that.layMain.height() - that.layMain.prop('clientHeight') > 0) {
					item.style.width = (parseFloat(item.style.width) - 1) + 'px';
				}
			});
		}

		that.loading(!0);
	};

	//重置表格尺寸/结构
	Class.prototype.resize = function() {
		var that = this;
		that.fullSize(); //让表格铺满
		that.setColsWidth(); //自适应列宽
		that.scrollPatch(); //滚动条补丁
	};

	//表格重载
	Class.prototype.reload = function(options) {
		var that = this;

		options = options || {};
		delete that.haveInit;

		if (options.data && options.data.constructor === Array) delete that.config.data;
		that.config = $.extend(true, {}, that.config, options);

		that.render();
	};

	//异常提示
	Class.prototype.errorView = function(html) {
		var that = this
			, elemNone = that.layMain.find('.' + NONE)
			, layNone = $('<div class="' + NONE + '">' + (html || 'Error') + '</div>');

		if (elemNone[0]) {
			that.layNone.remove();
			elemNone.remove();
		}

		that.layFixed.addClass(HIDE);
		that.layMain.find('tbody').html('');

		that.layMain.append(that.layNone = layNone);

		table.cache[that.key] = []; //格式化缓存数据
	};

	//页码
	Class.prototype.page = 1;

	//获得数据
	Class.prototype.pullData = function(curr) {
		var that = this
			, options = that.config
			, request = options.request
			, response = options.response
			, sort = function() {
				if (typeof options.initSort === 'object') {
					that.sort(options.initSort.field, options.initSort.type);
				}
			};

		that.startTime = new Date().getTime(); //渲染开始时间

		if (options.url) { //Ajax请求
			var params = {};
			params[request.pageName] = curr;
			params[request.limitName] = options.limit;

			//参数
			var data = $.extend(params, options.where);
			if (options.contentType && options.contentType.indexOf("application/json") == 0) { //提交 json 格式
				data = JSON.stringify(data);
			}

			that.loading();

			$.ajax({
				type: options.method || 'get'
				, url: options.url
				, contentType: options.contentType
				, data: data
				, dataType: 'json'
				, headers: options.headers || {}
				, success: function(res) {
					//如果有数据解析的回调，则获得其返回的数据
					if (typeof options.parseData === 'function') {
						res = options.parseData(res) || res;
					}
					//检查数据格式是否符合规范
					if (res[response.statusName] != response.statusCode) {
						that.renderForm();
						that.errorView(
							res[response.msgName] ||
							('返回的数据不符合规范，正确的成功状态码应为："' + response.statusName + '": ' + response.statusCode)
						);
					} else {
						that.renderData(res, curr, res[response.countName]), sort();
						options.time = (new Date().getTime() - that.startTime) + ' ms'; //耗时（接口请求+视图渲染）
					}
					that.setColsWidth();
					typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
				}
				, error: function(e, m) {
					that.errorView('数据接口请求异常：' + m);

					that.renderForm();
					that.setColsWidth();
				}
			});
		} else if (options.data && options.data.constructor === Array) { //已知数据
			var res = {}
				, startLimit = curr * options.limit - options.limit

			res[response.dataName] = options.data.concat().splice(startLimit, options.limit);
			res[response.countName] = options.data.length;

			//记录合计行数据
			if (typeof options.totalRow === 'object') {
				res[response.totalRowName] = $.extend({}, options.totalRow);
			}

			that.renderData(res, curr, res[response.countName]), sort();
			that.setColsWidth();
			typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
		}
	};

	//遍历表头
	Class.prototype.eachCols = function(callback) {
		var that = this;
		table.eachCols(null, callback, that.config.cols);
		return that;
	};

	//数据渲染
	Class.prototype.renderData = function(res, curr, count, sort) {
		var that = this
			, options = that.config
			, data = res[options.response.dataName] || [] //列表数据
			, totalRowData = res[options.response.totalRowName] //合计行数据
			, trs = []
			, trs_fixed = []
			, trs_fixed_r = []

			//渲染视图
			, render = function() { //后续性能提升的重点
				var thisCheckedRowIndex;
				if (!sort && that.sortKey) {
					return that.sort(that.sortKey.field, that.sortKey.sort, true);
				}
				layui.each(data, function(i1, item1) {
					var tds = [], tds_fixed = [], tds_fixed_r = []
						, numbers = i1 + options.limit * (curr - 1) + 1; //序号

					if (item1.length === 0) return;

					if (!sort) {
						item1[table.config.indexName] = i1;
					}

					that.eachCols(function(i3, item3) {
						var field = item3.field || i3
							, key = options.index + '-' + item3.key
							, content = item1[field];

						if (content === undefined || content === null) content = '';
						if (item3.colGroup) return;

						//td内容
						var td = ['<td data-field="' + field + '" data-key="' + key + '" ' + function() { //追加各种属性
							var attr = [];
							if (item3.edit) attr.push('data-edit="' + item3.edit + '"'); //是否允许单元格编辑
							if (item3.align) attr.push('align="' + item3.align + '"'); //对齐方式
							if (item3.templet) attr.push('data-content="' + content + '"'); //自定义模板
							if (item3.toolbar) attr.push('data-off="true"'); //行工具列关闭单元格事件
							if (item3.event) attr.push('lay-event="' + item3.event + '"'); //自定义事件
							if (item3.style) attr.push('style="' + item3.style + '"'); //自定义样式
							if (item3.minWidth) attr.push('data-minwidth="' + item3.minWidth + '"'); //单元格最小宽度
							return attr.join(' ');
						}() + ' class="' + function() { //追加样式
							var classNames = [];
							if (item3.hide) classNames.push(HIDE); //插入隐藏列样式
							if (!item3.field) classNames.push('layui-table-col-special'); //插入特殊列样式
							return classNames.join(' ');
						}() + '">'
							, '<div class="layui-table-cell laytable-cell-' + function() { //返回对应的CSS类标识
								return item3.type === 'normal' ? key
									: (key + ' laytable-cell-' + item3.type);
							}() + '">' + function() {
								var tplData = $.extend(true, {
									LAY_INDEX: numbers
								}, item1)
									, checkName = table.config.checkName;

								//渲染不同风格的列
								switch (item3.type) {
									case 'checkbox':
										return '<input type="checkbox" name="layTableCheckbox" lay-skin="primary" ' + function() {
											//如果是全选
											if (item3[checkName]) {
												item1[checkName] = item3[checkName];
												return item3[checkName] ? 'checked' : '';
											}
											return tplData[checkName] ? 'checked' : '';
										}() + '>';
										break;
									case 'radio':
										if (tplData[checkName]) {
											thisCheckedRowIndex = i1;
										}
										return '<input type="radio" name="layTableRadio_' + options.index + '" '
											+ (tplData[checkName] ? 'checked' : '') + ' lay-type="layTableRadio">';
										break;
									case 'numbers':
										return numbers;
										break;
								};

								//解析工具列模板
								if (item3.toolbar) {
									return laytpl($(item3.toolbar).html() || '').render(tplData);
								}
								return parseTempData(item3, content, tplData);
							}()
							, '</div></td>'].join('');

						tds.push(td);
						if (item3.fixed && item3.fixed !== 'right') tds_fixed.push(td);
						if (item3.fixed === 'right') tds_fixed_r.push(td);
					});

					trs.push('<tr data-index="' + i1 + '">' + tds.join('') + '</tr>');
					trs_fixed.push('<tr data-index="' + i1 + '">' + tds_fixed.join('') + '</tr>');
					trs_fixed_r.push('<tr data-index="' + i1 + '">' + tds_fixed_r.join('') + '</tr>');
				});

				that.layBody.scrollTop(0);
				that.layMain.find('.' + NONE).remove();
				that.layMain.find('tbody').html(trs.join(''));
				that.layFixLeft.find('tbody').html(trs_fixed.join(''));
				that.layFixRight.find('tbody').html(trs_fixed_r.join(''));

				that.renderForm();
				typeof thisCheckedRowIndex === 'number' && that.setThisRowChecked(thisCheckedRowIndex);
				that.syncCheckAll();

				//滚动条补丁
				that.haveInit ? that.scrollPatch() : setTimeout(function() {
					that.scrollPatch();
				}, 50);
				that.haveInit = true;

				layer.close(that.tipsIndex);

				//同步表头父列的相关值
				options.HAS_SET_COLS_PATCH || that.setColsPatch();
				options.HAS_SET_COLS_PATCH = true;
			};

		table.cache[that.key] = data; //记录数据

		//显示隐藏分页栏
		that.layPage[(count == 0 || (data.length === 0 && curr == 1)) ? 'addClass' : 'removeClass'](HIDE);

		//如果无数据
		if (data.length === 0) {
			that.renderForm();
			return that.errorView(options.text.none);
		} else {
			that.layFixed.removeClass(HIDE);
		}

		//如果执行初始排序
		if (sort) {
			return render();
		}

		//正常初始化数据渲染
		render(); //渲染数据
		that.renderTotal(data, totalRowData); //数据合计

		//同步分页状态
		if (options.page) {
			options.page = $.extend({
				elem: 'layui-table-page' + options.index
				, count: count
				, limit: options.limit
				, limits: options.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90]
				, groups: 3
				, layout: ['prev', 'page', 'next', 'skip', 'count', 'limit']
				, prev: '<i class="layui-icon">&#xe603;</i>'
				, next: '<i class="layui-icon">&#xe602;</i>'
				, jump: function(obj, first) {
					if (!first) {
						//分页本身并非需要做以下更新，下面参数的同步，主要是因为其它处理统一用到了它们
						//而并非用的是 options.page 中的参数（以确保分页未开启的情况仍能正常使用）
						that.page = obj.curr; //更新页码
						options.limit = obj.limit; //更新每页条数

						that.pullData(obj.curr);
					}
				}
			}, options.page);
			options.page.count = count; //更新总条数
			laypage.render(options.page);
		}
	};

	//数据合计行
	Class.prototype.renderTotal = function(data, totalRowData) {
		var that = this
			, options = that.config
			, totalNums = {};

		if (!options.totalRow) return;

		layui.each(data, function(i1, item1) {
			if (item1.length === 0) return;

			that.eachCols(function(i3, item3) {
				var field = item3.field || i3
					, content = item1[field];

				if (item3.totalRow) {
					totalNums[field] = (totalNums[field] || 0) + (parseFloat(content) || 0);
				}
			});
		});

		that.dataTotal = {};

		var tds = [];
		that.eachCols(function(i3, item3) {
			var field = item3.field || i3;

			//td内容
			var content = function() {
				var text = item3.totalRowText || ''
					, thisTotalNum = parseFloat(totalNums[field]).toFixed(2)
					, tplData = {};

				tplData[field] = thisTotalNum;
				thisTotalNum = parseTempData(item3, thisTotalNum, tplData);

				//如果直接传入了合计行数据，则不输出自动计算的结果
				if (totalRowData) {
					return totalRowData[item3.field] || text;
				} else {
					return item3.totalRow ? (thisTotalNum || text) : text;
				}
			}()
				, td = ['<td data-field="' + field + '" data-key="' + options.index + '-' + item3.key + '" ' + function() {
					var attr = [];
					if (item3.align) attr.push('align="' + item3.align + '"'); //对齐方式
					if (item3.style) attr.push('style="' + item3.style + '"'); //自定义样式
					if (item3.minWidth) attr.push('data-minwidth="' + item3.minWidth + '"'); //单元格最小宽度
					return attr.join(' ');
				}() + ' class="' + function() { //追加样式
					var classNames = [];
					if (item3.hide) classNames.push(HIDE); //插入隐藏列样式
					if (!item3.field) classNames.push('layui-table-col-special'); //插入特殊列样式
					return classNames.join(' ');
				}() + '">'
					, '<div class="layui-table-cell laytable-cell-' + function() { //返回对应的CSS类标识
						var str = (options.index + '-' + item3.key);
						return item3.type === 'normal' ? str
							: (str + ' laytable-cell-' + item3.type);
					}() + '">' + content
					, '</div></td>'].join('');

			item3.field && (that.dataTotal[field] = content);
			tds.push(td);
		});

		that.layTotal.find('tbody').html('<tr>' + tds.join('') + '</tr>');
	};

	//找到对应的列元素
	Class.prototype.getColElem = function(parent, key) {
		var that = this
			, options = that.config;
		return parent.eq(0).find('.laytable-cell-' + (options.index + '-' + key) + ':eq(0)');
	};

	//渲染表单
	Class.prototype.renderForm = function(type) {
		form.render(type, 'LAY-table-' + this.index);
	};

	//标记当前行选中状态
	Class.prototype.setThisRowChecked = function(index) {
		var that = this
			, options = that.config
			, ELEM_CLICK = 'layui-table-click'
			, tr = that.layBody.find('tr[data-index="' + index + '"]');

		tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK);
	};

	//数据排序
	Class.prototype.sort = function(th, type, pull, formEvent) {
		var that = this
			, field
			, res = {}
			, options = that.config
			, filter = options.elem.attr('lay-filter')
			, data = table.cache[that.key], thisData;

		//字段匹配
		if (typeof th === 'string') {
			that.layHeader.find('th').each(function(i, item) {
				var othis = $(this)
					, _field = othis.data('field');
				if (_field === th) {
					th = othis;
					field = _field;
					return false;
				}
			});
		}

		try {
			var field = field || th.data('field')
				, key = th.data('key');

			//如果欲执行的排序已在状态中，则不执行渲染
			if (that.sortKey && !pull) {
				if (field === that.sortKey.field && type === that.sortKey.sort) {
					return;
				}
			}

			var elemSort = that.layHeader.find('th .laytable-cell-' + key).find(ELEM_SORT);
			that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); //清除其它标题排序状态
			elemSort.attr('lay-sort', type || null);
			that.layFixed.find('th')
		} catch (e) {
			return hint.error('Table modules: Did not match to field');
		}

		//记录排序索引和类型
		that.sortKey = {
			field: field
			, sort: type
		};

		//默认为前端自动排序。如果否，则需自主排序（通常为服务端处理好排序）
		if (options.autoSort) {
			if (type === 'asc') { //升序
				thisData = layui.sort(data, field);
			} else if (type === 'desc') { //降序
				thisData = layui.sort(data, field, true);
			} else { //清除排序
				thisData = layui.sort(data, table.config.indexName);
				delete that.sortKey;
			}
		}

		res[options.response.dataName] = thisData || data;
		that.renderData(res, that.page, that.count, true);

		if (formEvent) {
			layui.event.call(th, MOD_NAME, 'sort(' + filter + ')', {
				field: field
				, type: type
			});
		}
	};

	//请求loading
	Class.prototype.loading = function(hide) {
		var that = this
			, options = that.config;
		if (options.loading) {
			if (hide) {
				that.layInit && that.layInit.remove();
				delete that.layInit;
				that.layBox.find(ELEM_INIT).remove();
			} else {
				that.layInit = $(['<div class="layui-table-init">'
					, '<i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>'
					, '</div>'].join(''));
				that.layBox.append(that.layInit);
			}
		}
	};

	//同步选中值状态
	Class.prototype.setCheckData = function(index, checked) {
		var that = this
			, options = that.config
			, thisData = table.cache[that.key];
		if (!thisData[index]) return;
		if (thisData[index].constructor === Array) return;
		thisData[index][options.checkName] = checked;
	};

	//同步全选按钮状态
	Class.prototype.syncCheckAll = function() {
		var that = this
			, options = that.config
			, checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]')
			, syncColsCheck = function(checked) {
				that.eachCols(function(i, item) {
					if (item.type === 'checkbox') {
						item[options.checkName] = checked;
					}
				});
				return checked;
			};

		if (!checkAllElem[0]) return;

		if (table.checkStatus(that.key).isAll) {
			if (!checkAllElem[0].checked) {
				checkAllElem.prop('checked', true);
				that.renderForm('checkbox');
			}
			syncColsCheck(true);
		} else {
			if (checkAllElem[0].checked) {
				checkAllElem.prop('checked', false);
				that.renderForm('checkbox');
			}
			syncColsCheck(false);
		}
	};

	//获取cssRule
	Class.prototype.getCssRule = function(key, callback) {
		var that = this
			, style = that.elem.find('style')[0]
			, sheet = style.sheet || style.styleSheet || {}
			, rules = sheet.cssRules || sheet.rules;
		layui.each(rules, function(i, item) {
			if (item.selectorText === ('.laytable-cell-' + key)) {
				return callback(item), true;
			}
		});
	};

	//让表格铺满
	Class.prototype.fullSize = function() {
		var that = this
			, options = that.config
			, height = options.height, bodyHeight;

		if (that.fullHeightGap) {
			height = _WIN.height() - that.fullHeightGap;
			if (height < 135) height = 135;
			that.elem.css('height', height);
		}

		if (!height) return;

		//减去列头区域的高度
		bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 38); //此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题，暂时只对默认尺寸的表格做支持。

		//减去工具栏的高度
		if (options.toolbar) {
			bodyHeight = bodyHeight - (that.layTool.outerHeight() || 50);
		}

		//减去统计朗的高度
		if (options.totalRow) {
			bodyHeight = bodyHeight - (that.layTotal.outerHeight() || 40);
		}

		//减去分页栏的高度
		if (options.page) {
			bodyHeight = bodyHeight - (that.layPage.outerHeight() || 41);
		}

		that.layMain.css('height', bodyHeight - 2);
	};

	//获取滚动条宽度
	Class.prototype.getScrollWidth = function(elem) {
		var width = 0;
		if (elem) {
			width = elem.offsetWidth - elem.clientWidth;
		} else {
			elem = document.createElement('div');
			elem.style.width = '100px';
			elem.style.height = '100px';
			elem.style.overflowY = 'scroll';

			document.body.appendChild(elem);
			width = elem.offsetWidth - elem.clientWidth;
			document.body.removeChild(elem);
		}
		return width;
	};

	//滚动条补丁
	Class.prototype.scrollPatch = function() {
		var that = this
			, layMainTable = that.layMain.children('table')
			, scollWidth = that.layMain.width() - that.layMain.prop('clientWidth') //纵向滚动条宽度
			, scollHeight = that.layMain.height() - that.layMain.prop('clientHeight') //横向滚动条高度
			, getScrollWidth = that.getScrollWidth(that.layMain[0]) //获取主容器滚动条宽度，如果有的话
			, outWidth = layMainTable.outerWidth() - that.layMain.width() //表格内容器的超出宽度

			//添加补丁
			, addPatch = function(elem) {
				if (scollWidth && scollHeight) {
					elem = elem.eq(0);
					if (!elem.find('.layui-table-patch')[0]) {
						var patchElem = $('<th class="layui-table-patch"><div class="layui-table-cell"></div></th>'); //补丁元素
						patchElem.find('div').css({
							width: scollWidth
						});
						elem.find('tr').append(patchElem);
					}
				} else {
					elem.find('.layui-table-patch').remove();
				}
			}

		addPatch(that.layHeader);
		addPatch(that.layTotal);

		//固定列区域高度
		var mainHeight = that.layMain.height()
			, fixHeight = mainHeight - scollHeight;
		that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() >= fixHeight ? fixHeight : 'auto');

		//表格宽度小于容器宽度时，隐藏固定列
		that.layFixRight[outWidth > 0 ? 'removeClass' : 'addClass'](HIDE);

		//操作栏
		that.layFixRight.css('right', scollWidth - 1);
	};

	//事件处理
	Class.prototype.events = function() {
		var that = this
			, options = that.config
			, _BODY = $('body')
			, dict = {}
			, th = that.layHeader.find('th')
			, resizing
			, ELEM_CELL = '.layui-table-cell'
			, filter = options.elem.attr('lay-filter');

		//工具栏操作事件
		that.layTool.on('click', '*[lay-event]', function(e) {
			var othis = $(this)
				, events = othis.attr('lay-event')
				, openPanel = function(sets) {
					var list = $(sets.list)
						, panel = $('<ul class="layui-table-tool-panel"></ul>');

					panel.html(list);

					//限制最大高度
					if (options.height) {
						panel.css('max-height', options.height - (that.layTool.outerHeight() || 50));
					}

					//插入元素
					othis.find('.layui-table-tool-panel')[0] || othis.append(panel);
					that.renderForm();

					panel.on('click', function(e) {
						layui.stope(e);
					});

					sets.done && sets.done(panel, list)
				};

			layui.stope(e);
			_DOC.trigger('table.tool.panel.remove');
			layer.close(that.tipsIndex);

			switch (events) {
				case 'LAYTABLE_COLS': //筛选列
					openPanel({
						list: function() {
							var lis = [];
							that.eachCols(function(i, item) {
								if (item.field && item.type == 'normal') {
									lis.push('<li><input type="checkbox" name="' + item.field + '" data-key="' + item.key + '" data-parentkey="' + (item.parentKey || '') + '" lay-skin="primary" ' + (item.hide ? '' : 'checked') + ' title="' + (item.title || item.field) + '" lay-filter="LAY_TABLE_TOOL_COLS"></li>');
								}
							});
							return lis.join('');
						}()
						, done: function() {
							form.on('checkbox(LAY_TABLE_TOOL_COLS)', function(obj) {
								var othis = $(obj.elem)
									, checked = this.checked
									, key = othis.data('key')
									, parentKey = othis.data('parentkey');

								layui.each(options.cols, function(i1, item1) {
									layui.each(item1, function(i2, item2) {
										if (i1 + '-' + i2 === key) {
											var hide = item2.hide;

											//同步勾选列的 hide 值和隐藏样式
											item2.hide = !checked;
											that.elem.find('*[data-key="' + options.index + '-' + key + '"]')
											[checked ? 'removeClass' : 'addClass'](HIDE);

											//根据列的显示隐藏，同步多级表头的父级相关属性值
											if (hide != item2.hide) {
												that.setParentCol(!checked, parentKey);
											}

											//重新适配尺寸
											that.resize();
										}
									});
								});
							});
						}
					});
					break;
				case 'LAYTABLE_EXPORT': //导出
					if (device.ie) {
						layer.tips('导出功能不支持 IE，请用 Chrome 等高级浏览器导出', this, {
							tips: 3
						})
					} else {
						openPanel({
							list: function() {
								return [
									'<li data-type="csv">导出到 Csv 文件</li>'
									, '<li data-type="xls">导出到 Excel 文件</li>'
								].join('')
							}()
							, done: function(panel, list) {
								list.on('click', function() {
									var type = $(this).data('type')
									table.exportFile.call(that, options.id, null, type);
								});
							}
						});
					}
					break;
				case 'LAYTABLE_PRINT': //打印
					var printWin = window.open('打印窗口', '_blank')
						, style = ['<style>'
							, 'body{font-size: 12px; color: #666;}'
							, 'table{width: 100%; border-collapse: collapse; border-spacing: 0;}'
							, 'th,td{line-height: 20px; padding: 9px 15px; border: 1px solid #ccc; text-align: left; font-size: 12px; color: #666;}'
							, 'a{color: #666; text-decoration:none;}'
							, '*.layui-hide{display: none}'
							, '</style>'].join('')
						, html = $(that.layHeader.html()); //输出表头

					html.append(that.layMain.find('table').html()); //输出表体
					html.append(that.layTotal.find('table').html()) //输出合计行

					html.find('th.layui-table-patch').remove(); //移除补丁
					html.find('.layui-table-col-special').remove(); //移除特殊列

					printWin.document.write(style + html.prop('outerHTML'));
					printWin.document.close();
					printWin.print();
					printWin.close();
					break;
			}

			layui.event.call(this, MOD_NAME, 'toolbar(' + filter + ')', $.extend({
				event: events
				, config: options
			}, {}));
		});

		//拖拽调整宽度    
		th.on('mousemove', function(e) {
			var othis = $(this)
				, oLeft = othis.offset().left
				, pLeft = e.clientX - oLeft;
			if (othis.data('unresize') || dict.resizeStart) {
				return;
			}
			dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域
			_BODY.css('cursor', (dict.allowResize ? 'col-resize' : ''));
		}).on('mouseleave', function() {
			var othis = $(this);
			if (dict.resizeStart) return;
			_BODY.css('cursor', '');
		}).on('mousedown', function(e) {
			var othis = $(this);
			if (dict.allowResize) {
				var key = othis.data('key');
				e.preventDefault();
				dict.resizeStart = true; //开始拖拽
				dict.offset = [e.clientX, e.clientY]; //记录初始坐标

				that.getCssRule(key, function(item) {
					var width = item.style.width || othis.outerWidth();
					dict.rule = item;
					dict.ruleWidth = parseFloat(width);
					dict.minWidth = othis.data('minwidth') || options.cellMinWidth;
				});
			}
		});

		//拖拽中
		_DOC.on('mousemove', function(e) {
			if (dict.resizeStart) {
				e.preventDefault();
				if (dict.rule) {
					var setWidth = dict.ruleWidth + e.clientX - dict.offset[0];
					if (setWidth < dict.minWidth) setWidth = dict.minWidth;
					dict.rule.style.width = setWidth + 'px';
					layer.close(that.tipsIndex);
				}
				resizing = 1
			}
		}).on('mouseup', function(e) {
			if (dict.resizeStart) {
				dict = {};
				_BODY.css('cursor', '');
				that.scrollPatch();
			}
			if (resizing === 2) {
				resizing = null;
			}
		});

		//排序
		th.on('click', function(e) {
			var othis = $(this)
				, elemSort = othis.find(ELEM_SORT)
				, nowType = elemSort.attr('lay-sort')
				, type;

			if (!elemSort[0] || resizing === 1) return resizing = 2;

			if (nowType === 'asc') {
				type = 'desc';
			} else if (nowType === 'desc') {
				type = null;
			} else {
				type = 'asc';
			}
			that.sort(othis, type, null, true);
		}).find(ELEM_SORT + ' .layui-edge ').on('click', function(e) {
			var othis = $(this)
				, index = othis.index()
				, field = othis.parents('th').eq(0).data('field')
			layui.stope(e);
			if (index === 0) {
				that.sort(field, 'asc', null, true);
			} else {
				that.sort(field, 'desc', null, true);
			}
		});

		//数据行中的事件监听返回的公共对象成员
		var commonMember = function(sets) {
			var othis = $(this)
				, index = othis.parents('tr').eq(0).data('index')
				, tr = that.layBody.find('tr[data-index="' + index + '"]')
				, data = table.cache[that.key] || [];


			data = data[index] || {};

			return $.extend({
				tr: tr //行元素
				, data: table.clearCacheKey(data) //当前行数据
				, del: function() { //删除行数据
					table.cache[that.key][index] = [];
					tr.remove();
					that.scrollPatch();
				}
				, update: function(fields) { //修改行数据
					fields = fields || {};
					layui.each(fields, function(key, value) {
						if (key in data) {
							var templet, td = tr.children('td[data-field="' + key + '"]');
							data[key] = value;
							that.eachCols(function(i, item2) {
								if (item2.field == key && item2.templet) {
									templet = item2.templet;
								}
							});
							td.children(ELEM_CELL).html(parseTempData({
								templet: templet
							}, value, data));
							td.data('content', value);
						}
					});
				}
			}, sets);
		};

		//复选框选择
		that.elem.on('click', 'input[name="layTableCheckbox"]+', function() { //替代元素的 click 事件
			var checkbox = $(this).prev()
				, childs = that.layBody.find('input[name="layTableCheckbox"]')
				, index = checkbox.parents('tr').eq(0).data('index')
				, checked = checkbox[0].checked
				, isAll = checkbox.attr('lay-filter') === 'layTableAllChoose';

			//全选
			if (isAll) {
				childs.each(function(i, item) {
					item.checked = checked;
					that.setCheckData(i, checked);
				});
				that.syncCheckAll();
				that.renderForm('checkbox');
			} else {
				that.setCheckData(index, checked);
				that.syncCheckAll();
			}

			layui.event.call(checkbox[0], MOD_NAME, 'checkbox(' + filter + ')', commonMember.call(checkbox[0], {
				checked: checked
				, type: isAll ? 'all' : 'one'
			}));
		});

		//单选框选择
		that.elem.on('click', 'input[lay-type="layTableRadio"]+', function() {
			var radio = $(this).prev()
				, checked = radio[0].checked
				, thisData = table.cache[that.key]
				, index = radio.parents('tr').eq(0).data('index');

			//重置数据单选属性
			layui.each(thisData, function(i, item) {
				if (index === i) {
					item.LAY_CHECKED = true;
				} else {
					delete item.LAY_CHECKED;
				}
			});
			that.setThisRowChecked(index);

			layui.event.call(this, MOD_NAME, 'radio(' + filter + ')', commonMember.call(this, {
				checked: checked
			}));
		});

		//行事件
		that.layBody.on('mouseenter', 'tr', function() { //鼠标移入行
			var othis = $(this)
				, index = othis.index();
			if (othis.data('off')) return; //不触发事件
			that.layBody.find('tr:eq(' + index + ')').addClass(ELEM_HOVER)
		}).on('mouseleave', 'tr', function() { //鼠标移出行
			var othis = $(this)
				, index = othis.index();
			if (othis.data('off')) return; //不触发事件
			that.layBody.find('tr:eq(' + index + ')').removeClass(ELEM_HOVER)
		}).on('click', 'tr', function() { //单击行
			setRowEvent.call(this, 'row');
		}).on('dblclick', 'tr', function() { //双击行
			setRowEvent.call(this, 'rowDouble');
		});

		//创建行单击、双击事件监听
		var setRowEvent = function(eventType) {
			var othis = $(this);
			if (othis.data('off')) return; //不触发事件
			layui.event.call(this,
				MOD_NAME, eventType + '(' + filter + ')'
				, commonMember.call(othis.children('td')[0])
			);
		};

		//单元格编辑
		that.layBody.on('change', '.' + ELEM_EDIT, function() {
			var othis = $(this)
				, value = this.value
				, field = othis.parent().data('field')
				, index = othis.parents('tr').eq(0).data('index')
				, data = table.cache[that.key][index];

			data[field] = value; //更新缓存中的值

			layui.event.call(this, MOD_NAME, 'edit(' + filter + ')', commonMember.call(this, {
				value: value
				, field: field
			}));
		}).on('blur', '.' + ELEM_EDIT, function() {
			var templet
				, othis = $(this)
				, thisElem = this
				, field = othis.parent().data('field')
				, index = othis.parents('tr').eq(0).data('index')
				, data = table.cache[that.key][index];
			that.eachCols(function(i, item) {
				if (item.field == field && item.templet) {
					templet = item.templet;
				}
			});
			othis.siblings(ELEM_CELL).html(function(value) {
				return parseTempData({
					templet: templet
				}, value, data);
			}(thisElem.value));
			othis.parent().data('content', thisElem.value);
			othis.remove();
		});

		//单元格单击事件
		that.layBody.on('click', 'td', function(e) {
			var othis = $(this)
				, field = othis.data('field')
				, editType = othis.data('edit')
				, elemCell = othis.children(ELEM_CELL);

			if (othis.data('off')) return; //不触发事件

			//显示编辑表单
			if (editType) {
				var input = $('<input class="layui-input ' + ELEM_EDIT + '">');
				input[0].value = othis.data('content') || elemCell.text();
				othis.find('.' + ELEM_EDIT)[0] || othis.append(input);
				input.focus();
				layui.stope(e);
				return;
			}
		}).on('mouseenter', 'td', function() {
			gridExpand.call(this)
		}).on('mouseleave', 'td', function() {
			gridExpand.call(this, 'hide');
		});

		//单元格展开图标
		var ELEM_GRID = 'layui-table-grid', ELEM_GRID_DOWN = 'layui-table-grid-down', ELEM_GRID_PANEL = 'layui-table-grid-panel'
			, gridExpand = function(hide) {
				var othis = $(this)
					, elemCell = othis.children(ELEM_CELL);

				if (othis.data('off')) return; //不触发事件

				if (hide) {
					othis.find('.layui-table-grid-down').remove();
				} else if (elemCell.prop('scrollWidth') > elemCell.outerWidth()) {
					if (elemCell.find('.' + ELEM_GRID_DOWN)[0]) return;
					othis.append('<div class="' + ELEM_GRID_DOWN + '"><i class="layui-icon layui-icon-down"></i></div>');
				}
			};

		//单元格展开事件
		that.layBody.on('click', '.' + ELEM_GRID_DOWN, function(e) {
			var othis = $(this)
				, td = othis.parent()
				, elemCell = td.children(ELEM_CELL);

			that.tipsIndex = layer.tips([
				'<div class="layui-table-tips-main" style="margin-top: -' + (elemCell.height() + 16) + 'px;' + function() {
					if (options.size === 'sm') {
						return 'padding: 4px 15px; font-size: 12px;';
					}
					if (options.size === 'lg') {
						return 'padding: 14px 15px;';
					}
					return '';
				}() + '">'
				, elemCell.html()
				, '</div>'
				, '<i class="layui-icon layui-table-tips-c layui-icon-close"></i>'
			].join(''), elemCell[0], {
				tips: [3, '']
				, time: -1
				, anim: -1
				, maxWidth: (device.ios || device.android) ? 300 : that.elem.width() / 2
				, isOutAnim: false
				, skin: 'layui-table-tips'
				, success: function(layero, index) {
					layero.find('.layui-table-tips-c').on('click', function() {
						layer.close(index);
					});
				}
			});

			layui.stope(e);
		});

		//行工具条操作事件
		that.layBody.on('click', '*[lay-event]', function() {
			var othis = $(this)
				, index = othis.parents('tr').eq(0).data('index');
			layui.event.call(this, MOD_NAME, 'tool(' + filter + ')', commonMember.call(this, {
				event: othis.attr('lay-event')
			}));
			that.setThisRowChecked(index);
		});

		//同步滚动条
		that.layMain.on('scroll', function() {
			var othis = $(this)
				, scrollLeft = othis.scrollLeft()
				, scrollTop = othis.scrollTop();

			that.layHeader.scrollLeft(scrollLeft);
			that.layTotal.scrollLeft(scrollLeft);
			that.layFixed.find(ELEM_BODY).scrollTop(scrollTop);

			layer.close(that.tipsIndex);
		});

		//自适应
		_WIN.on('resize', function() {
			that.resize();
		});
	};

	//一次性事件
	; (function() {
		//全局点击
		_DOC.on('click', function() {
			_DOC.trigger('table.remove.tool.panel');
		});

		//工具面板移除事件
		_DOC.on('table.remove.tool.panel', function() {
			$('.layui-table-tool-panel').remove();
		});
	})();

	//初始化
	table.init = function(filter, settings) {
		settings = settings || {};
		var that = this
			, elemTable = filter ? $('table[lay-filter="' + filter + '"]') : $(ELEM + '[lay-data]')
			, errorTips = 'Table element property lay-data configuration item has a syntax error: ';

		//遍历数据表格
		elemTable.each(function() {
			var othis = $(this), tableData = othis.attr('lay-data');

			try {
				tableData = new Function('return ' + tableData)();
			} catch (e) {
				hint.error(errorTips + tableData)
			}

			var cols = [], options = $.extend({
				elem: this
				, cols: []
				, data: []
				, skin: othis.attr('lay-skin') //风格
				, size: othis.attr('lay-size') //尺寸
				, even: typeof othis.attr('lay-even') === 'string' //偶数行背景
			}, table.config, settings, tableData);

			filter && othis.hide();

			//获取表头数据
			othis.find('thead>tr').each(function(i) {
				options.cols[i] = [];
				$(this).children().each(function(ii) {
					var th = $(this), itemData = th.attr('lay-data');

					try {
						itemData = new Function('return ' + itemData)();
					} catch (e) {
						return hint.error(errorTips + itemData)
					}

					var row = $.extend({
						title: th.text()
						, colspan: th.attr('colspan') || 0 //列单元格
						, rowspan: th.attr('rowspan') || 0 //行单元格
					}, itemData);

					if (row.colspan < 2) cols.push(row);
					options.cols[i].push(row);
				});
			});

			//获取表体数据
			othis.find('tbody>tr').each(function(i1) {
				var tr = $(this), row = {};
				//如果定义了字段名
				tr.children('td').each(function(i2, item2) {
					var td = $(this)
						, field = td.data('field');
					if (field) {
						return row[field] = td.html();
					}
				});
				//如果未定义字段名
				layui.each(cols, function(i3, item3) {
					var td = tr.children('td').eq(i3);
					row[item3.field] = td.html();
				});
				options.data[i1] = row;
			});
			table.render(options);
		});

		return that;
	};

	//记录所有实例
	thisTable.that = {}; //记录所有实例对象
	thisTable.config = {}; //记录所有实例配置项

	//遍历表头
	table.eachCols = function(id, callback, cols) {
		var config = thisTable.config[id] || {}
			, arrs = [], index = 0;

		cols = $.extend(true, [], cols || config.cols);

		//重新整理表头结构
		layui.each(cols, function(i1, item1) {
			layui.each(item1, function(i2, item2) {

				//如果是组合列，则捕获对应的子列
				if (item2.colGroup) {
					var childIndex = 0;
					index++
					item2.CHILD_COLS = [];

					layui.each(cols[i1 + 1], function(i22, item22) {
						//如果子列已经被标注为{PARENT_COL_INDEX}，或者子列累计 colspan 数等于父列定义的 colspan，则跳出当前子列循环
						if (item22.PARENT_COL_INDEX || (childIndex > 1 && childIndex == item2.colspan)) return;

						item22.PARENT_COL_INDEX = index;

						item2.CHILD_COLS.push(item22);
						childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1);
					});
				}

				if (item2.PARENT_COL_INDEX) return; //如果是子列，则不进行追加，因为已经存储在父列中
				arrs.push(item2)
			});
		});

		//重新遍历列，如果有子列，则进入递归
		var eachArrs = function(obj) {
			layui.each(obj || arrs, function(i, item) {
				if (item.CHILD_COLS) return eachArrs(item.CHILD_COLS);
				typeof callback === 'function' && callback(i, item);
			});
		};

		eachArrs();
	};

	//表格选中状态
	table.checkStatus = function(id) {
		var nums = 0
			, invalidNum = 0
			, arr = []
			, data = table.cache[id] || [];
		//计算全选个数
		layui.each(data, function(i, item) {
			if (item.constructor === Array) {
				invalidNum++; //无效数据，或已删除的
				return;
			}
			if (item[table.config.checkName]) {
				nums++;
				arr.push(table.clearCacheKey(item));
			}
		});
		return {
			data: arr //选中的数据
			, isAll: data.length ? (nums === (data.length - invalidNum)) : false //是否全选
		};
	};

	//表格导出
	table.exportFile = function(id, data, type) {
		var that = this;

		data = data || table.clearCacheKey(table.cache[id]);
		type = type || 'csv';

		var config = thisTable.config[id] || {}
			, textType = ({
				csv: 'text/csv'
				, xls: 'application/vnd.ms-excel'
			})[type]
			, alink = document.createElement("a");

		if (device.ie) return hint.error('IE_NOT_SUPPORT_EXPORTS');

		alink.href = 'data:' + textType + ';charset=utf-8,\ufeff' + encodeURIComponent(function() {
			var dataTitle = [], dataMain = [], dataTotal = [];

			//表头和表体
			layui.each(data, function(i1, item1) {
				var vals = [];
				if (typeof id === 'object') { //如果 id 参数直接为表头数据
					layui.each(id, function(i, item) {
						i1 == 0 && dataTitle.push(item || '');
					});
					layui.each(table.clearCacheKey(item1), function(i2, item2) {
						vals.push('"' + (item2 || '') + '"');
					});
				} else {
					table.eachCols(id, function(i3, item3) {
						if (item3.field && item3.type == 'normal' && !item3.hide) {
							var content = item1[item3.field];
							if (content === undefined || content === null) content = '';

							i1 == 0 && dataTitle.push(item3.title || '');
							vals.push('"' + parseTempData(item3, content, item1, 'text') + '"');
						}
					});
				}
				dataMain.push(vals.join(','));
			});

			//表合计
			layui.each(that.dataTotal, function(key, value) {
				dataTotal.push(value);
			});

			return dataTitle.join(',') + '\r\n' + dataMain.join('\r\n') + '\r\n' + dataTotal.join(',');
		}());

		alink.download = (config.title || 'table_' + (config.index || '')) + '.' + type;
		document.body.appendChild(alink);
		alink.click();
		document.body.removeChild(alink);
	};

	//重置表格尺寸结构
	table.resize = function(id) {
		//如果指定表格唯一 id，则只执行该 id 对应的表格实例
		if (id) {
			var config = getThisTableConfig(id); //获取当前实例配置项
			if (!config) return;

			thisTable.that[id].resize();

		} else { //否则重置所有表格实例尺寸
			layui.each(thisTable.that, function() {
				this.resize();
			});
		}
	};

	//表格重载
	table.reload = function(id, options) {
		var config = getThisTableConfig(id); //获取当前实例配置项
		if (!config) return;

		var that = thisTable.that[id];
		that.reload(options);

		return thisTable.call(that);
	};

	//核心入口
	table.render = function(options) {
		var inst = new Class(options);
		return thisTable.call(inst);
	};

	//清除临时Key
	table.clearCacheKey = function(data) {
		data = $.extend({}, data);
		delete data[table.config.checkName];
		delete data[table.config.indexName];
		return data;
	};

	//新增获取列信息
	table.getThat = function(id) {
		var config = getThisTableConfig(id); //获取当前实例配置项
		if (!config) return null;
		return thisTable.that[id];
	};
	
	table.getThatConfig = function(id) {
		var config = getThisTableConfig(id); //获取当前实例配置项
		if (!config) return null;
		return config;
	};
	
	//自动完成渲染
	table.init();

	exports(MOD_NAME, table);
});


